import { i18n } from 'boot/i18n'
import Qs from 'qs'
import { Notify, throttle } from 'quasar'
import { userStores } from 'src/stores/user-stores'
import { createDialog } from 'src/utils/utils'
import { clearPendingMap, removePending } from './cancelRepeatRquest'

let isLogon = false, cloneAxios = null
const requesting = [], loginList = ['118', '119', '401']

/**
 * 表单序列化
 */
export const serialize = data => {
  const list = []
  Object.keys(data).forEach(ele => list.push(`${ele}=${data[ele]}`))
  return list.join('&')
}

// getPendingKey ：用于根据当前请求的信息，生成请求 Key；
export const getPendingKey = config => {
  // 响应的时候，response.config 中的data 是一个JSON字符串，所以需要转换一下
  if (config && config.data && isJsonStr(config.data)) config.data = JSON.parse(config.data)
  const { method, url, params, data } = config // 请求方式，参数，请求地址，
  return [method, url, Qs.stringify(params), Qs.stringify(data)].join('&') // 拼接
}

// 判断一个字符串是否为JSON字符串
export const isJsonStr = str => {
  if (typeof str === 'string') {
    try {
      const obj = JSON.parse(str)
      return !!(typeof obj === 'object' && obj)
      // eslint-disable-next-line no-unused-vars
    } catch (e) {
      return false
    }
  }
}

/**
 * 报错信息处理
 */
export const getReturn = res => {
  Notify.create({ type: 'negative', message: res.msg || res.message || res.error || res })
  return Promise.reject(res)
}

/**
 * 取消重新登录或登录失败
 */
const cancelLogin = () => {
  isLogon = false
  Promise.resolve().then(() => {
    requesting.forEach(request => request(removePending, true))
    requesting.splice(0)
    clearPendingMap()
  })
}

/**
 * Token 到期重新登录
 */
const againLogin = throttle(res => {
  if (isLogon) return
  isLogon = true
  const { userInfo, LoginByName } = userStores()
  createDialog({
    msg: res.msg || res.statusText || res.message || res, okLabel: i18n.t('Login'), cancelLabel: i18n.t('Close'),
    prompt: {
      model: '', outlined: true, placeholder: i18n.t('Password'), isValid: val => val.length > 0,
      type: 'password', autofocus: true
    }
  }, async val => {
    const loginForm = { loginName: userInfo.loginName, tenantId: userInfo.tenantId, password: val }
    await LoginByName(loginForm).then(() => {
      isLogon = false
      Promise.resolve().then(() => {
        requesting.forEach(request => request(cloneAxios))
        requesting.splice(0)
        clearPendingMap()
      })
    }).catch(() => cancelLogin())
  }, () => cancelLogin())
}, 2000)

const setRequesting = res => {
  againLogin(res.data)
  return new Promise((resolve, reject) => requesting.push((reload, cancel) => {
    (cancel && reject(new Error())) || resolve(reload(res.config))
  }))
}

const requestHandle = res => {
  if ([200, 201, 500].includes(res.status)) {
    if (!res.data.code) return res.status === 500 ? responseHandle('500', res.data) : responseHandle('blob', res)
    return responseHandle(res.data.code, res.data)
  }
  return responseHandle(res.status, res.data)
}

export const refreshToken = (res, axios) => {
  cloneAxios = axios
  if (res.status === 401) return setRequesting(res)
  if (res.data?.code === '-1' && loginList.includes(res.data?.data?.businessCode)) return setRequesting(res)
  return requestHandle(res)
}

/**
 * 接口 code 返回处理
 */
export const responseHandle = (code, res) => {
  code = `${code}`
  if (['blob'].includes(code)) return res
  if (['0', '200', '201'].includes(code)) return res.data
  if (['-1', '401'].includes(code)) {
    if (code === '401' || loginList.includes(res.data?.businessCode)) againLogin(res)
    else return getReturn(res)
    return Promise.reject(res)
  }
  if (['404', '503'].includes(code)) return getReturn(code === '404' ? '404' : i18n.t('AxiosTip'))
  if (['413'].includes(code)) return getReturn(i18n.t('UnknownError', ['413']))
  if (['500', '502'].includes(code)) return getReturn(res)
  return getReturn(res)
}